﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Solidi
{
	/// <summary>
	/// Thread safe
	/// </summary>
	public sealed class DependencyContainer : IDependencyContainer
	{
		private IDependencyRegistry _registry;
		private IDependencyResolver _resolver;
		private IDependencyComposer _composer;
		private IDependencyLifetime _lifetime;

		public DependencyContainer(IDependencyRegistry registry, IDependencyResolver resolver, IDependencyComposer composer, IDependencyLifetime lifetime)
		{
			if (registry == null)
			{
				throw new ArgumentNullException("registry");
			}

			if (resolver == null)
			{
				throw new ArgumentNullException("resolver");
			}

			if (composer == null)
			{
				throw new ArgumentNullException("composer");
			}

			if (lifetime == null)
			{
				throw new ArgumentNullException("lifetime");
			}

			_registry = registry;
			_resolver = resolver;
			_composer = composer;
			_lifetime = lifetime;
		}

		public DependencyContainer()
			: this(DefaultRegistry(), DefaultResolver(), DefaultComposer(), DefaultLifetime())
		{

		}

		public static IDependencyContainer FromBuilder(IDependencyBuilder builder)
		{
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }

			IDependencyContainer container =  new DependencyContainer(DefaultRegistry(), DefaultResolver(), DefaultComposer(), DefaultLifetime());

			container.Registry.Add(builder.Dependencies);

			return container;
		}

		private static IDependencyRegistry DefaultRegistry()
		{
			IDependencyRegistry registry = new DependencyRegistry();

			registry = new AutoDependencyRegistry(registry);
			registry = new ListDependencyRegistry(registry);

			return registry;
		}

		public void Dispose()
		{
			Lifetime.DiscardAll(this, true);
		}

		private static IDependencyResolver DefaultResolver()
		{
			IDependencyResolver resolver = new DependencyResolver();

            resolver = new FuncDependencyResolver(resolver);
			resolver = new LazyDependencyResolver(resolver);
			resolver = new CircularDependencyResolver(resolver);

			return resolver;
		}

		private static IDependencyComposer DefaultComposer()
		{
			IDependencyComposer composer = new DependencyComposer();

			composer = new PropertyDependencyComposer(composer);

			return composer;
		}

		private static IDependencyLifetime DefaultLifetime()
		{
			return new DependencyLifetime();
		}

		public IDependencyRegistry Registry { get { return _registry; } }

		public IDependencyResolver Resolver { get { return _resolver; } }

		public IDependencyComposer Composer { get { return _composer; } }

		public IDependencyLifetime Lifetime { get { return _lifetime; } }
	}
}
